package com.demo0_求激光切割的块数;


import java.util.ArrayList;

/**
 * 1.先对字符串进行切割, 以M 作为标志
 * 2.根据切割的字符串数组, 每个进行遍历. 并且生成对应的边的对象, 装入集合. 每次从集合中获取上一条边对象
 * 3.最后遍历每一个点的坐标, 看是否可以形成正方形.
 *   并且进行特殊边的判断, 最边上的边需要特殊判断.
 *
 * 审题 要看清楚......
 */
public class Test {

    public static void main(String[] args) {

        int height=3;//rows
        int width=4; //column
        String operations="MRMOMDMLMUMCRMODMC";
        int[] distances={1,1,2,1,2,2,1,2};

/*
        int height=3;//rows
        int width=4;//column
        String operations="MRMOMDMLMUMC";
        int[] distances={1,1,2,1,2,2};
*/

        int result = edgeTest(height, width, operations, distances);
        System.out.println("一共有"+result+"个方块");

    }
    //根据坐标判断是否该点有正方形. 用该点生成4条边,用字符串的方式., 依次判断每一条边,是否在集合中. 都在则,
    public static int edgeTest(int rows,int column,String operations,int[] distances){

        //1.调用方法生成初始化集合.
        ArrayList<Edge> edgeList = initString(column, rows);
        System.out.println("初始化集合:"+edgeList);
        //2.根据操作生成对应的运行边
        ArrayList<Edge> operationsEdgeList = edgeListResult(operations, distances, 0, 0);
        System.out.println("结果集合:"+operationsEdgeList);
        //3.将两个集合合并.
        edgeList.addAll(operationsEdgeList);
        System.out.println("最后的集合:"+edgeList);
        //4.循环进行判断
        int count=0;
        for (int i = 0; i <= column-1; i++) {
            for (int j = 0; j <= rows-1; j++) {
                //4.1 根据坐标生成一个 边集合
                ArrayList<Edge> edgeArrayList = getSegment(i, j);
                int number=0;
                //4.2 依次遍历这个集合看是否每一条边都可以在我们的运行生成的边集合里
                for (int k = 0; k < edgeArrayList.size(); k++) {
                    //4.3 对口字型边中的一条边进行与操作边集合进行遍历
                    for (int n = 0; n < edgeList.size(); n++) {
                        if(edgeArrayList.get(k).equals(edgeList.get(n))){
                            //有一个匹配到.
                            number++;
                            break;
                        }
                    }
                }
                // 如果找到4条都匹配的, 说明有一个正方形.
                if(number==4){
                    count++;
                }
            }
        }
        //5.返回结果
        return count;
    }
    //根据坐标生成一个口字型的切割线段: 测试没有问题.
    public static ArrayList<Edge> getSegment(int x,int y){
        //1.设置运行字符串
        String operations = "MORMUML";
        //2.设置运行距离
        int[] distances = {1,1,1};
        //3.调用方法获得集合
        ArrayList<Edge> edgeList = edgeList(operations, distances, x, y);
        //4.将集合中的第一条边的状态改为切割
        Edge firstEdge = new Edge(x, y, x, y+1, 1);
        edgeList.set(0,firstEdge);
        //5.返回集合
        return edgeList;
    }


    //集合初始化.最好也可以用一个方法来生成.
    public static ArrayList<Edge> initString(int x, int y){
        //根据x,y 可以生成对应的字符串 口字型字符串
        String s="";
        for (int i = 0; i < y-1; i++) {
            s +="MD";
        }

        for (int i = 0; i < x; i++) {
            s+="MR";
        }

        for (int i = 0; i < y; i++) {
            s+="MU";
        }

        for (int i = 0; i < x; i++) {
            s +="ML";
        }

        int[] ints = new int[2 * (x + y)];
        for (int i = 0; i < ints.length; i++) {
            ints[i]=1;
        }
        ArrayList<Edge> arrayList = edgeList(s, ints, 0, 0);
        for (int i = 0; i < arrayList.size(); i++) {
            arrayList.get(i).setStatus(1);
        }

        return arrayList;


    }

    /*根据路径,移动距离,开始坐标,这4个参数, 生成边集合.并返回一个集合. */
    public static ArrayList<Edge> edgeList(String operations,int[] distances,int startX,int startY){
        //1.解析字符串
        String[] strs = splitString(operations);
        //初始方向向下,激光刀默认初始为关闭.初始边为0.0
        boolean isOpen = false;
        char direction = 'D';
        int initStartX =startX;
        int initStartY =startY;
        int initEndX =startX;
        int initEndY =startY+1;

        Edge lastedge = new Edge(initStartX, initStartY, initEndX, initEndY, 1);
        ArrayList<Edge> edgeArrayList = new ArrayList<>();
        //加入初始边, 由初始边向下的第一条边.
        edgeArrayList.add(lastedge);
        //开始遍历并生成边
        for (int i = 0; i < strs.length; i++) {
            //判断当前字符串中是否包开启激光
            if(strs[i].contains("C")){
                isOpen=false;
            }
            if(strs[i].contains("O")){
                isOpen=true;
            }
            for (int j = 0; j < distances[i]; j++) {
                //获取边
                Edge edge = getEdge(strs[i], lastedge);
                if(isOpen){
                    edge.setStatus(1);
                }else {
                    edge.setStatus(0);
                }
                //把结果边加入集合
                edgeArrayList.add(edge);
                //从集合中获取最后一条边
                lastedge=edgeArrayList.get(edgeArrayList.size()-1);
            }
        }
        return edgeArrayList;
    }

    public static ArrayList<Edge> edgeListResult(String operations,int[] distances,int startX,int startY){
        //0.对运行路径集合做一个预调整
        //拷贝下标从1开始
        int[] ints = new int[splitString(operations).length];
        for (int i = 1; i < distances.length; i++) {
            ints[i-1]=distances[i];
        }
        //1.解析字符串
        String[] strs = splitString(operations);
        //初始方向向下,激光刀默认初始为关闭.初始边为0.0
        boolean isOpen = false;

        //生成第一个坐标的路径线段,以及对应的长度.
        String s="";
        for (int i = 0; i < ints[0]-1; i++) {
            s+="MD";
        }
        int[] dis=new int[ints[0]-1];
        for (int i = 0; i < dis.length; i++) {
            dis[i]=1;
        }
        ArrayList<Edge> listFrist = edgeList(s, dis, 0, 0);
        Edge lastedge = listFrist.get(listFrist.size() - 1);
        //开始遍历并生成边
        for (int i = 0; i < strs.length; i++) {
            //判断当前字符串中是否包开启激光
            if(strs[i].contains("C")){
                isOpen=false;
            }
            if(strs[i].contains("O")){
                isOpen=true;
            }
            for (int j = 0; j < ints[i]; j++) {
                //获取边
                Edge edge = getEdge(strs[i], lastedge);
                if(isOpen){
                    edge.setStatus(1);
                }else {
                    edge.setStatus(0);
                }
                //把结果边加入集合
                listFrist.add(edge);
                //从集合中获取最后一条边
                lastedge=listFrist.get(listFrist.size()-1);
            }
        }
        return listFrist;
    }

    //1.对字符串进行切割放入数组
    public static String[] splitString(String s){
        String[] strings = s.split("M");
        for (int i = 0; i < strings.length; i++) {
            strings[i]="M"+strings[i];
        }
        String[] result = new String[strings.length-1];
        for (int i = 0; i < result.length; i++) {
            result[i]=strings[i+1];
        }
        return result;
    }
    //2.生成边
    public static  Edge getEdge(String s,Edge edgeLast){

        //获取对应的解析的字符
        char chr = getChar(s);
        //获取对应的终点边
        int[] xy = getXY(chr, edgeLast);
        //新建一个边对象
        Edge edge = new Edge();
        //起点
        edge.setStartX(edgeLast.endX);
        edge.setStartY(edgeLast.endY);
        //终点
        edge.setEndX(xy[0]);
        edge.setEndY(xy[1]);

        return edge;
    }
    //3.对字符串进行映射 为字符
    public static char getChar(String s){
        if (s.contains("U")){
            return 'U';
        }else if(s.contains("D")){
            return 'D';
        }else if(s.contains("L")){
            return 'L';
        }else if(s.contains("R")){
            return 'R';
        }else {
            return 0;
        }
    }
    //生成边的后两个坐标: 数组的第一个是 X, 第二个是Y
    public static int[] getXY(char chr,Edge edge){
        int endX=0;
        int endY=0;
        switch (chr){
            case 'U':
                endX=edge.getEndX();
                endY=edge.getEndY()-1;
                break;
            case 'D':
                endX=edge.getEndX();
                endY=edge.getEndY()+1;
                break;
            case 'L':
                endX=edge.getEndX()-1;
                endY=edge.getEndY();
                break;
            case 'R':
                endX=edge.getEndX()+1;
                endY=edge.getEndY();
                break;
            case 0:
                endX=edge.endX+(edge.endX-edge.startX);
                endY=edge.endY+(edge.endY-edge.startY);
                break;
        }

        return new int[]{endX, endY};
    }
}
